package wstest;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;


import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.websocket.WebSocket;

import predictors.SubmitJob;

import data.*;
import jsonobj.*;

import utils.ClientFunctions;
import utils.ClusterFunctions;
import utils.Database;
import utils.Msg;
import utils.Utils;

public class SireWebSocket implements WebSocket, JSonObj, Msg {
	private String uname;
	private String hostname;
	private Outbound out = null;
	private UserInfo ui;
	private ClusterInfo ci;
	private boolean login;
	private boolean isCluster = false;
	private Connection conn = null;
	private ClientFunctions cf;
	private ClusterFunctions cuf;
	private Thread ping;

	public SireWebSocket(String hostname) {
		this.hostname = hostname;
	}

	public void onConnect(Outbound outbound) {
		MySQLconnect();
		out = outbound;
		login = false;
		cf = new ClientFunctions();
		cuf = new ClusterFunctions();
		ping = new Ping();
	}

	public void onMessage(byte frame, byte[] data, int offset, int length) {
		onMessage(frame, TypeUtil.toHexString(data, offset, length));
	}

	public void onMessage(byte frame, String data) {
		try {
			
			String[] tokens = data.split("\\|");
			byte obj_type = Byte.parseByte(tokens[0]);
			if(obj_type==PING)
				return;
			
			String json = tokens[1];
			/*System.out.println("[RECEIVED]");
			System.out.println("----------");
			for (String s : tokens) {
				System.out.println(s);
			}
			System.out.println("----------");*/
			
			
			if (!login) {
				switch (obj_type) {
				case CLI_REGISTER: {
					Response res = cf.registerUser(conn,
							RegisterInfo.fromJSon(json));
					out.sendMessage(res.toString());
					break;
				}
				case CLI_LOGIN: {
					//Utils.out("in login");
					Object o = cf.userLogin(conn, LoginInfo.fromJSon(json));
					Utils.out(o.toString());
					if (o instanceof Response)
						out.sendMessage(((Response) o).toString());
					else {
						ui = (UserInfo) o;
						out.sendMessage(new Response(true, OK).toString());
						ui.generateClusterList(conn);
						out.sendMessage(ui.toString());
						ui.out = this.out;
						login = true;
						ui.isConnected = true;
						ping.start();
					}
					break;
				}
				case CLU_LOGIN: {
					Object[] objs = cuf.clusterLogin(conn,
							ClusterLoginInfo.fromJson(json), hostname);
					Response res = (Response) objs[0];
					if (res.success) {
						ui = (UserInfo) objs[1];
						ci = (ClusterInfo) objs[2];

						login = true;
						ci.out = this.out;
						ci.isConnected = true;
						isCluster = true;
						ping.start();
						if(ui.isConnected)
							ui.sendClusterInfo(conn);
					}
					out.sendMessage(res.toString());
					break;
				}
				}
			} else {
				switch (obj_type) {
				case CLI_JOB_SUB: {
					Utils.exec.execute(new SubmitJob(ui,JobInfo.fromJSon(json)));
					break;

				}
				case CLI_MSG: {
					Message m = Message.fromJson(json);
					ClusterInfo cinfo = ui.clusters.get(m.toHost);
					if (cinfo.isConnected)
						cinfo.sendMessage(m);
					break;
				}
				case CLI_LOGOUT: {
					ui.isConnected = false;
					System.out.println("LOGOUT "
							+ Database.users.get(uname).isConnected);
					login = false;
					ui.sendMessage(new Response(true, OK));
					break;
				}
				case CLU_MSG: {
					if (ui.isConnected)
						ui.sendMessage(Message.fromJson(json));
					break;
				}
				case CLU_ST_INFO:
				{
					Database.addClusterStatusInfo(conn, hostname,ClusterStatusInfo.fromJSon(json));
					break;
				}
				case CLU_JOB_INFO:
				{
					Database.addMyJobsInfo(conn, hostname,MyJobInfo.fromJSon(json));
					break;
				}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			/*
			 * if(!isCluster && login) { ui.disconnect(); } else if(isCluster &&
			 * login) { ci.disconnect(); }
			 */
		}
	}

	public void onDisconnect() {

		if (login) {
			login = false;
			if (!isCluster) {
				System.out.println("\n+ User "+ui.username+": DISCONNECTED\n");
				ui.isConnected = false;
				ui.disconnect();
			} else {
				System.out.println("\n+ Cluster "+ci.local_hostname+": DISCONNECTED\n");
				ui.clusters.remove(ci);
				if (ui.isConnected) {
					try {
						ui.sendMessage(new Message(Msg.CLUSTER_OFF,
								ci.hostname,ci.local_hostname));
					} catch (Exception e) {
					}
				}
				ci.isConnected = false;
			}
		}
		try{
			if(conn != null)
				conn.close();
		}catch(Exception e){}
	}

	public void onFragment(boolean more, byte opcode, byte[] data, int offset,
			int length) {
	}
	
	class Ping extends Thread {
		public void run() {
			while (true)
				try {
					Thread.sleep(60*1000);
					if(!login) break;
					if(!isCluster)
						ui.sendClusterInfo(conn);
					else
						ci.sendMessage(PING+"|0");
				}catch(Exception e) {return;}
		}
	}

	public void MySQLconnect() {
		try {
			String url = "jdbc:mysql://127.0.0.1/sire";
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(url, "root", "");
			/*stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
					ResultSet.CONCUR_UPDATABLE);*/
			Utils.out("< Connection to SQL server: OK >");

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
